home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / spatial / game.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  8.7 KB  |  404 lines

  1. /* (C) Copyright 1991 Andrew Plotkin. Permission is
  2.  given to copy and use, as long as this copyright
  3.  notice is retained. */
  4.  
  5. #include <stdio.h>
  6. #include <sys/time.h>
  7. #include <X11/Xlib.h>
  8. #include <X11/keysym.h>
  9. #include "spatial.h"
  10.  
  11. #define TICKLENGTH (25000)
  12. #define GLIDELENGTH (8)
  13. #define TURNLENGTH (8)
  14. #define PLUMLENGTH (3)
  15. #define FALLLENGTH (8)
  16. #define PI (3.141593)
  17.  
  18. int stereo;
  19.  
  20. int meterx, meterx2, metery, metersize, meterlev, meteroldlev,
  21. meter_f_b, meter_b_d; /* oldlev is level on fieldpm */
  22.  
  23. unsigned char field[MAXFIELDXY][MAXFIELDXY][MAXFIELDZ];
  24. short fieldx, fieldy, fieldz;
  25. double fieldoffx, fieldoffx2, fieldoffy, fieldoffz;
  26. extern double offx, offy, offz;
  27. long score=(-1), dropticks;
  28.  
  29. extern void plop_piece(), setup_cubies(), redo_board_globals();
  30. extern void setup_fieldpm(), clearfield(),
  31. back_to_disp(), setup_backpm();
  32. extern void startpiece(), rotate_piece(),
  33. updatetemp_tra(), updatepiece(), round_piece();
  34. extern void pauseloop();
  35. extern int collision();
  36.  
  37. void clearfield()
  38. {
  39.     int ix, iy, iz;
  40.     for (ix=0; ix<fieldx; ix++)
  41.     for (iy=0; iy<fieldy; iy++)
  42.         for (iz=0; iz<fieldz; iz++) 
  43.         field[ix][iy][iz] = 0;
  44. }
  45.  
  46. void initgame()
  47. {
  48.     curpiece = -1;
  49.     score = 0;
  50.     dropticks = 80;
  51.     meterlev = 0;
  52.     clearfield();
  53.     setup_cubies();
  54.     setup_fieldpm();
  55. }
  56.  
  57. void gameloop()
  58. {
  59. #define ST_STILL (0)
  60. #define ST_FALL (1)
  61. #define ST_TURN (2)
  62. #define ST_GLIDE (3)
  63. #define ST_PLUMMET (4)
  64. #define ST_SPACEHIT (5)
  65. #define ST_PAUSE (6)
  66.  
  67.     short status, res, aighhmode=0;
  68.     short droptimer=0, stattick;
  69.     Bool eventp;
  70.     XEvent event, nextevent;
  71.     long evmasks;
  72.     char key;
  73.     KeySym ksym;
  74.     long lasttime;
  75.     int toffx, toffy, toffz;
  76.     int taxis; /* 1=x, 2=y, 3=z */
  77.     int tdir;
  78.     struct timeval tv;
  79.     fd_set readbits;
  80.     int gotit;
  81.  
  82.     status = ST_PAUSE;
  83.     /*lasttime = current_usec();*/
  84.  
  85.     while (1) {
  86.     if (curpiece==(-1)) {
  87.         startpiece();
  88.         if (curpiece==(-2)) break;
  89.         setup_backpm();
  90.         draw_score(backpm);
  91.         draw_score(win);
  92.         back_to_disp(0);
  93.         droptimer = 0;
  94.  
  95.         do {
  96.         eventp = XCheckWindowEvent(dpy,
  97.             win, KeyPressMask, &event);
  98.         }
  99.         while (eventp);
  100.     };
  101.  
  102.     XFlush(dpy);
  103.  
  104.     tv.tv_sec = 0;
  105.     tv.tv_usec = TICKLENGTH;
  106.     FD_ZERO(&readbits);
  107.     FD_SET(ConnectionNumber(dpy), &readbits);
  108.     (void)select(1+ConnectionNumber(dpy), &readbits, 0, 0, &tv);
  109.  
  110.     if (status == ST_STILL)
  111.         evmasks = (KeyPressMask | ExposureMask |
  112.                StructureNotifyMask);
  113.     else
  114.         evmasks = (ExposureMask | StructureNotifyMask);
  115.  
  116.     if (eventp = XCheckWindowEvent(dpy, win, evmasks, &event))
  117.       switch (event.type) {
  118.         case Expose:
  119.         do {
  120.             gotit = XCheckWindowEvent(dpy, win,
  121.             ExposureMask, &nextevent);
  122.         } while (gotit);
  123.         back_to_disp(1);
  124.         break;
  125.         case KeyPress:
  126.         XLookupString(&event, &key, 1, &ksym, NULL);
  127.         switch (ksym) {
  128.             case XK_Q:
  129.             case XK_q:
  130.             return;
  131.             break;
  132.             case XK_Escape:
  133.             pauseloop();
  134.             setup_fieldpm();
  135.             redraw_cubies();   
  136.             setup_backpm();
  137.             draw_score(backpm);
  138.             draw_score(win);
  139.             back_to_disp(1);            
  140.             break;
  141.             case XK_asciitilde:
  142.             aighhmode = (!aighhmode);
  143.             break;
  144.             case XK_h:
  145.             case XK_j:
  146.             case XK_k:
  147.             case XK_l:
  148.             case XK_i:
  149.             case XK_m:
  150.             if (status != ST_STILL) break;
  151.             if (ksym==XK_i || ksym==XK_m) taxis=1;
  152.             if (ksym==XK_h || ksym==XK_l) taxis=2;
  153.             if (ksym==XK_j || ksym==XK_k) taxis=3;
  154.             if (ksym==XK_i || ksym==XK_h || ksym==XK_k)
  155.                 tdir=1;
  156.             else tdir=(-1);
  157.             toffx = 0;
  158.             toffy = 0;
  159.             toffz = 0;
  160.             updatetemp_tra(toffx, toffy, toffz, taxis,
  161.                        tdir);
  162.             res = collision(1);
  163.             while (res==1 || (res>=3 && res <=6)) {
  164.                 switch (res) {
  165.                 case 1:
  166.                     toffz--;
  167.                     break;
  168.                 case 3:
  169.                     toffy++;
  170.                     break;
  171.                 case 4:
  172.                     toffy--;
  173.                     break;
  174.                 case 5:
  175.                     toffx--;
  176.                     break;
  177.                 case 6:
  178.                     toffx++;
  179.                     break;
  180.                 }
  181.                 updatetemp_tra(toffx, toffy, toffz,
  182.                        taxis, tdir);
  183.                 res = collision(1);
  184.             };
  185.             if (res==0) {
  186.                 status = ST_TURN;
  187.                 stattick = 0;
  188.             };
  189.             break;
  190.             case XK_p:
  191.             if (status != ST_STILL) break;
  192.             droptimer = dropticks+100;
  193.             break;
  194.             case XK_space:
  195.             if (status != ST_STILL) break;
  196.             status = ST_SPACEHIT;
  197.             break;
  198.             case XK_Left:
  199.             case XK_Right:
  200.             case XK_Up:
  201.             case XK_Down:
  202.             if (status != ST_STILL) break;
  203.             toffx = 0;
  204.             toffy = 0;
  205.             if (ksym==XK_Left) toffx = -1;
  206.             if (ksym==XK_Right) toffx = 1;
  207.             if (ksym==XK_Up) toffy = -1;
  208.             if (ksym==XK_Down) toffy = 1;
  209.             updatetemp_tra(toffx, toffy, 0, 0, 0);
  210.             if (collision(1)==0) {
  211.                 status = ST_GLIDE;
  212.                 stattick = 0;
  213.             };
  214.             break;
  215.         };
  216.         break;
  217.         case ConfigureNotify:
  218.         if (event.xconfigure.width != dispx || event.xconfigure.height != dispy) {
  219.             dispx = event.xconfigure.width;
  220.             dispy = event.xconfigure.height;
  221.             XFreePixmap(dpy, backpm);
  222.             XFreePixmap(dpy, fieldpm);
  223.             backpm = XCreatePixmap(dpy, win,
  224.             dispx, dispy, scndepth);   
  225.             fieldpm = XCreatePixmap(dpy, win,
  226.             dispx, dispy, scndepth);   
  227.             redo_board_globals();
  228.             setup_cubies();
  229.             setup_fieldpm();
  230.             redraw_cubies();   
  231.             setup_backpm();
  232.             draw_score(backpm);
  233.             draw_score(win);
  234.             back_to_disp(1);            
  235.         }
  236.         break;
  237.         default:
  238.         break;
  239.     }
  240.  
  241.     {
  242.         if (status==ST_PAUSE) status=ST_STILL;
  243.         switch (status) {
  244.         case ST_STILL:
  245.             droptimer++;
  246.             if (droptimer>dropticks) {
  247.             droptimer=0;
  248.             updatetemp_tra(0, 0, -1, 0, 0);
  249.             if (collision(1)==0) {  
  250.                 stattick=0;
  251.                 status = ST_FALL;
  252.             }
  253.             else {
  254.                 plop_piece();
  255.                 curpiece = -1;
  256.             }
  257.             }
  258.             break;
  259.         case ST_SPACEHIT:
  260.             updatetemp_tra(0, 0, -1, 0, 0);
  261.             if (aighhmode || collision(1)==0) {  
  262.             score++;
  263.             stattick=1;
  264.             status = ST_PLUMMET;
  265.             offz -= 1.0/PLUMLENGTH;
  266.             if (offz < -(fieldz+300.0)) {
  267.                 fprintf(stderr,
  268.                 "Vanishing point error\nSegmentation fault\n");
  269.                 exit(-1);
  270.             }
  271.             updatepiece();
  272.             setup_backpm();
  273.             back_to_disp(0);
  274.             }
  275.             else {
  276.             plop_piece();
  277.             curpiece = -1;
  278.             status = ST_PAUSE;
  279.             }
  280.             break;
  281.         case ST_GLIDE:
  282.             stattick++;
  283.             offx += (double)toffx/GLIDELENGTH;
  284.             offy += (double)toffy/GLIDELENGTH;
  285.             if (stattick==GLIDELENGTH) {
  286.             round_piece(); 
  287.             };
  288.             updatepiece();
  289.             setup_backpm();
  290.             back_to_disp(0);
  291.             if (stattick==GLIDELENGTH) {
  292.             status = ST_PAUSE;
  293.             };
  294.             break;
  295.         case ST_FALL:
  296.             stattick++;
  297.             offz -= 1.0/FALLLENGTH;
  298.             if (stattick==FALLLENGTH) {
  299.             round_piece(); 
  300.             };
  301.             updatepiece();
  302.             setup_backpm();
  303.             back_to_disp(0);
  304.             if (stattick==FALLLENGTH) {
  305.             status = ST_PAUSE;
  306.             };
  307.             break;
  308.         case ST_PLUMMET:
  309.             stattick++;
  310.             offz -= 1.0/PLUMLENGTH;
  311.             if (stattick==PLUMLENGTH) {
  312.             round_piece(); 
  313.             };
  314.             updatepiece();
  315.             setup_backpm();
  316.             back_to_disp(0);
  317.             if (stattick==PLUMLENGTH) {
  318.             status = ST_SPACEHIT;
  319.             };
  320.             break;
  321.         case ST_TURN:
  322.             stattick++;
  323.             rotate_piece(taxis, tdir*0.5*PI/TURNLENGTH);
  324.             offx += (double)toffx/TURNLENGTH;
  325.             offy += (double)toffy/TURNLENGTH;
  326.             offz += (double)toffz/TURNLENGTH;
  327.             if (stattick==TURNLENGTH) {
  328.             round_piece(); 
  329.             };
  330.             updatepiece();
  331.             setup_backpm();
  332.             back_to_disp(0);
  333.             if (stattick==TURNLENGTH) {
  334.             status = ST_PAUSE;
  335.             };
  336.             break;
  337.         }
  338.         /*lasttime = current_usec();*/        
  339.     }
  340.     }
  341. }
  342.  
  343. void redo_board_globals()  /* using dispx, dispy */
  344. {
  345.     if (!stereo) {
  346.     if (dispy-40<dispx-20) 
  347.         boardscale = (double)(dispy - 40);
  348.     else
  349.         boardscale = (double)(dispx - 20);
  350.     halfboard = (int)boardscale/2;
  351.     }
  352.     else {
  353.     if (dispy-40<(dispx-20)/2)
  354.         boardscale = (double)(dispy - 40);
  355.     else
  356.         boardscale = (double)((dispx - 20)/2);
  357.     halfboard = (int)boardscale/2;
  358.     halfboard2 = (3.0+(fieldoffx+2.5)/1.5)*halfboard;
  359.     }
  360.     if (dispy-(int)boardscale > 60) {
  361.     meterx = 32;
  362.     metery = boardscale+30;
  363.     }
  364.     else {
  365.     meterx = 176;
  366.     metery = boardscale+10;
  367.     }
  368.     metersize = (((int)boardscale) - meterx) / fieldz;
  369.     if (metersize<1) metersize = 1;
  370.     if (stereo) {
  371.     meterx2 = meterx + (halfboard2 - halfboard);
  372.     /*meterx2 = meterx2 & (~7);*/
  373.     }
  374. }
  375.  
  376. long current_usec() /* returns the current
  377.  time in microseconds */ 
  378. {
  379.     struct timeval tv;
  380.  
  381.     gettimeofday(&tv, (struct timezone *)NULL);
  382.     return tv.tv_usec + 1000000*(tv.tv_sec%100);
  383. }
  384.  
  385. int elapsed(start, length) /* returns whether
  386.  length microseconds have elapsed since start.
  387.  Not reliable when length is more than 10^8 usec
  388.  (100 seconds) */
  389. long start, length;
  390. {
  391.     long now;
  392.  
  393.     now = current_usec();
  394.     if (start <= now) {
  395.     if (now-start > length) return 1;
  396.     else return 0;
  397.     }
  398.     else {  /* the current time has rolled
  399.      over; add 10^8 to it */
  400.     if (now+100000000-start > length) return 1;
  401.     else return 0;
  402.     }
  403. }
  404.